/**
 * Title: jFamilyTree SQL provider
 * Description: jFamilyTree SQL provider
 * About: Designed and rewritten by Andreas Lundgren, based on the Treebolic application suite
 * Copyright: (c) 2001-2008
 * Terms of use:see license agreement at http://treebolic.sourceforge.net/en/license.htm
 * Author: Bernard Bou
 * Company: bsys
 */
package jFamilyTree.provider.sql;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.table.TableModel;

/**
 * SQL statement dialog
 * 
 * @author Bernard Bou
 */
public class SqlDialog extends JDialog
{
	private static final long serialVersionUID = 1L;

	/**
	 * Attributes
	 */
	private String[][] theNameValues = new String[][] { //
	{ "nodes.id", null }, //
			{ "nodes.label", null }, //
			{ "nodes.content", null }, //
			{ "nodes.backcolor", null }, //
			{ "nodes.forecolor", null }, //
			{ "nodes.image", null }, //
			{ "nodes.link", null }, //
			{ "nodes.target", null }, //
			{ "nodes.weight", null }, //
			{ "nodes.mountpoint", null }, //
			{ "nodes.mountnow", null }, //

			{ "edges.istree", null }, //
			{ "edges.from", null }, //
			{ "edges.to", null }, //
			{ "edges.label", null }, //
			{ "edges.image", null }, //
			{ "edges.color", null }, //
			{ "edges.hidden", null }, //
			{ "edges.stroke", null }, //
			{ "edges.fromterminator", null }, //
			{ "edges.toterminator", null }, //

			{ "settings.backimage", null }, //
			{ "settings.backcolor", null }, //
			{ "settings.forecolor", null }, //
			{ "settings.fontface", null }, //
			{ "settings.fontsize", null }, //
			{ "settings.fontsizestep", null }, //
			{ "settings.orientation", null }, //
			{ "settings.expansion", null }, //
			{ "settings.sweep", null }, //
			{ "settings.preserveorientation", null }, //
			{ "settings.hyperbolic", null }, //
			{ "settings.hastoolbar", null }, //
			{ "settings.hasstatusbar", null }, //
			{ "settings.haspopupmenu", null }, //
			{ "settings.hastooltip", null }, //
			{ "settings.tooltipdisplayscontent", null }, //
			{ "settings.focusonhover", null }, //
			{ "settings.focus", null }, //
			{ "settings.xmoveto", null }, //
			{ "settings.ymoveto", null }, //
			{ "settings.xshift", null }, //
			{ "settings.yshift", null }, //
			{ "settings.nodebackcolor", null }, //
			{ "settings.nodeforecolor", null }, //
			{ "settings.nodeimage", null }, //
			{ "settings.treeedgecolor", null }, //
			{ "settings.treeedgehidden", null }, //
			{ "settings.treeedgestroke", null }, //
			{ "settings.treeedgefromterminator", null }, //
			{ "settings.treeedgetoterminator", null }, //
			{ "settings.treeedgeimage", null }, //
			{ "settings.edgecolor", null }, //
			{ "settings.edgehidden", null }, //
			{ "settings.edgestroke", null }, //
			{ "settings.edgefromterminator", null }, //
			{ "settings.edgetoterminator", null }, //
			{ "settings.edgeimage", null }, //

			{ "menu.action", null }, //
			{ "menu.label", null }, //
			{ "menu.target", null }, //
			{ "menu.scope", null }, //
			{ "menu.mode", null }, //
			{ "menu.link", null }, //
	};

	/**
	 * Ok button pressed
	 */
	public boolean ok;

	/**
	 * Property file
	 */
	private String thePropertyUrlString;

	/**
	 * URL combo box
	 */
	private JTextField theURLField;

	/**
	 * Querier text area
	 */
	private JTextField theUserTextField;

	/**
	 * Password field
	 */
	private JPasswordField thePasswdField;

	/**
	 * Name table
	 */
	private JTable theNameTable;

	/**
	 * Nodes SQL statement text area
	 */
	private JTextArea theNodesSqlTextArea;

	/**
	 * Tree Edges SQL statement text area
	 */
	private JTextArea theTreeEdgesSqlTextArea;

	/**
	 * Edges SQL statement text area
	 */
	private JTextArea theEdgesSqlTextArea;

	/**
	 * Settings SQL statement text area
	 */
	private JTextArea theSettingsSqlTextArea;

	/**
	 * Constructor
	 * 
	 * @param thisPropertyUrlString
	 *        property file string
	 */
	public SqlDialog(String thisPropertyUrlString)
	{
		super((JFrame) null, true);
		ok = false;
		thePropertyUrlString = thisPropertyUrlString;
		theURLField = new JTextField();
		theUserTextField = new JTextField();
		thePasswdField = new JPasswordField();
		theNodesSqlTextArea = new JTextArea();
		theTreeEdgesSqlTextArea = new JTextArea();
		theEdgesSqlTextArea = new JTextArea();
		theSettingsSqlTextArea = new JTextArea();
		theNameTable = new JTable(theNameValues, new String[] { "name", "value" });

		initialize();
		load();
	}

	/**
	 * Initialize
	 * 
	 * @throws Exception
	 */
	private void initialize()
	{
		JLabel thisTitleLabel = new JLabel("jFamilyTree SQL provider");
		thisTitleLabel.setFont(new Font("Dialog", Font.BOLD, 16));
		thisTitleLabel.setHorizontalAlignment(SwingConstants.CENTER);
		thisTitleLabel.setHorizontalTextPosition(SwingConstants.CENTER);

		JLabel thisURLLabel = new JLabel("URL");
		JLabel thisUserLabel = new JLabel("User");
		JLabel thisPasswdLabel = new JLabel("Password");
		JLabel thisSqlLabel = new JLabel("SQL");
		JLabel thisMapLabel = new JLabel("Field names");

		theURLField.setEditable(true);
		theURLField.setToolTipText("URL for data source");

		theUserTextField.setToolTipText("user to query database as");
		theUserTextField.setText("user");

		thePasswdField.setToolTipText(null);
		thePasswdField.setText("password to query database");

		theNodesSqlTextArea.setEditable(true);
		theNodesSqlTextArea.setLineWrap(true);
		theNodesSqlTextArea.setWrapStyleWord(true);
		theNodesSqlTextArea.setRequestFocusEnabled(true);
		theNodesSqlTextArea.setToolTipText("SQL statement selecting nodes");
		theNodesSqlTextArea.setText(null);
		theNodesSqlTextArea.setRows(4);

		theTreeEdgesSqlTextArea.setEditable(true);
		theTreeEdgesSqlTextArea.setLineWrap(true);
		theTreeEdgesSqlTextArea.setWrapStyleWord(true);
		theTreeEdgesSqlTextArea.setRequestFocusEnabled(true);
		theTreeEdgesSqlTextArea.setToolTipText("SQL statement selecting tree edges");
		theTreeEdgesSqlTextArea.setText(null);
		theTreeEdgesSqlTextArea.setRows(4);

		theEdgesSqlTextArea.setEditable(true);
		theEdgesSqlTextArea.setLineWrap(true);
		theEdgesSqlTextArea.setWrapStyleWord(true);
		theEdgesSqlTextArea.setRequestFocusEnabled(true);
		theEdgesSqlTextArea.setToolTipText("SQL statement selecting edges");
		theEdgesSqlTextArea.setText(null);
		theEdgesSqlTextArea.setRows(4);

		theSettingsSqlTextArea.setEditable(true);
		theSettingsSqlTextArea.setLineWrap(true);
		theSettingsSqlTextArea.setWrapStyleWord(true);
		theSettingsSqlTextArea.setRequestFocusEnabled(true);
		theSettingsSqlTextArea.setToolTipText("SQL statement selecting settings");
		theSettingsSqlTextArea.setText(null);
		theSettingsSqlTextArea.setRows(4);

		JScrollPane thisNodesSqlScrollPane = new JScrollPane(theNodesSqlTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		JScrollPane thisTreeEdgesSqlScrollPane = new JScrollPane(theTreeEdgesSqlTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		JScrollPane thisEdgesSqlScrollPane = new JScrollPane(theEdgesSqlTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		JScrollPane thisSettingsSqlScrollPane = new JScrollPane(theSettingsSqlTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		thisNodesSqlScrollPane.setBorder(null);
		thisTreeEdgesSqlScrollPane.setBorder(null);
		thisEdgesSqlScrollPane.setBorder(null);
		thisSettingsSqlScrollPane.setBorder(null);

		JTabbedPane thisTabbedPane = new JTabbedPane();
		thisTabbedPane.add("Nodes", thisNodesSqlScrollPane);
		thisTabbedPane.add("TreeEdges", thisTreeEdgesSqlScrollPane);
		thisTabbedPane.add("Edges", thisEdgesSqlScrollPane);
		thisTabbedPane.add("Settings", thisSettingsSqlScrollPane);

		theNameTable.setToolTipText("Database field representing node id");
		JScrollPane thisMapsSqlScrollPane = new JScrollPane(theNameTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		thisMapsSqlScrollPane.setPreferredSize(new Dimension(500, 100));

		JButton theOkButton = new JButton();
		theOkButton.setText("Ok");
		theOkButton.addActionListener(new ActionListener()
		{
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
			 */
			public void actionPerformed(ActionEvent e)
			{
				ok = true;
				setVisible(false);
			}
		});

		JButton theCancelButton = new JButton();
		theCancelButton.setText("Cancel");
		theCancelButton.addActionListener(new ActionListener()
		{
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
			 */
			public void actionPerformed(ActionEvent e)
			{
				setVisible(false);
			}
		});

		JButton theLoadButton = new JButton();
		theLoadButton.setText("Load");
		theLoadButton.addActionListener(new ActionListener()
		{
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
			 */
			public void actionPerformed(ActionEvent e)
			{
				JFileChooser thisFileChooser = new JFileChooser();
				thisFileChooser.setFileFilter(new javax.swing.filechooser.FileFilter()
				{
					/*
					 * (non-Javadoc)
					 * 
					 * @see javax.swing.filechooser.FileFilter#accept(java.io.File)
					 */
					public boolean accept(File thisFile)
					{
						return thisFile.getName().toLowerCase().endsWith(".properties") || thisFile.isDirectory();
					}

					/*
					 * (non-Javadoc)
					 * 
					 * @see javax.swing.filechooser.FileFilter#getDescription()
					 */
					public String getDescription()
					{
						return "Property files";
					}
				});
				thisFileChooser.setDialogTitle("jFamilyTreeSQl");
				thisFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				thisFileChooser.setCurrentDirectory(new File("."));
				if (thisFileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
				{
					try
					{
						thePropertyUrlString = thisFileChooser.getSelectedFile().toURI().toURL().toString();
						load();
					}
					catch (MalformedURLException thisException)
					{
					}
				}
			}
		});
		JPanel thisButtonPanel = new JPanel();
		thisButtonPanel.setLayout(new FlowLayout());
		thisButtonPanel.add(theLoadButton);
		thisButtonPanel.add(theCancelButton);
		thisButtonPanel.add(theOkButton);

		JPanel thisPanel = new JPanel();
		thisPanel.setLayout(new GridBagLayout());
		thisPanel.add(thisTitleLabel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 20, 5), 0, 0));

		thisPanel.add(thisURLLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(thisUserLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 1));
		thisPanel.add(thisPasswdLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(thisSqlLabel, new GridBagConstraints(0, 5, 1, 5, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(thisMapLabel, new GridBagConstraints(0, 20, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));

		thisPanel.add(theURLField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(theUserTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(thePasswdField, new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 200, 0));
		thisPanel.add(thisTabbedPane, new GridBagConstraints(1, 5, 1, 5, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
		thisPanel.add(thisMapsSqlScrollPane, new GridBagConstraints(1, 20, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));

		thisPanel.add(thisButtonPanel, new GridBagConstraints(0, 25, 2, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));

		setContentPane(thisPanel);
	}

	/**
	 * Get properties
	 * 
	 * @return properties
	 */
	public Properties getProperties()
	{
		Properties theseProperties = new Properties();
		theseProperties.put("url", theURLField.getText() == null ? "" : theURLField.getText());
		theseProperties.put("user", theUserTextField.getText());
		theseProperties.put("passwd", new String(thePasswdField.getPassword()));
		theseProperties.put("nodesSql", theNodesSqlTextArea.getText());
		theseProperties.put("treeedgesSql", theTreeEdgesSqlTextArea.getText());
		theseProperties.put("edgesSql", theEdgesSqlTextArea.getText());
		theseProperties.put("settingsSql", theSettingsSqlTextArea.getText());
		TableModel thisModel = theNameTable.getModel();
		int thisRowIndex = 0;
		for (String[] thisRow : theNameValues)
		{
			String thisKey = thisRow[0];
			String thisValue = (String) thisModel.getValueAt(thisRowIndex, 1);
			if (thisValue != null)
				theseProperties.setProperty(thisKey, thisValue);
			thisRowIndex++;
		}
		return theseProperties;
	}

	/**
	 * Set properties
	 * 
	 * @param theseProperties
	 *        properties
	 */
	public void setProperties(Properties theseProperties)
	{
		theURLField.setText((String) theseProperties.get("url"));
		theUserTextField.setText((String) theseProperties.get("user"));
		thePasswdField.setText((String) theseProperties.get("passwd"));
		theNodesSqlTextArea.setText((String) theseProperties.get("nodesSql"));
		theTreeEdgesSqlTextArea.setText((String) theseProperties.get("treeEdgesSql"));
		theEdgesSqlTextArea.setText((String) theseProperties.get("edgesSql"));
		theSettingsSqlTextArea.setText((String) theseProperties.get("settingsSql"));
		TableModel thisModel = theNameTable.getModel();
		int thisRowIndex = 0;
		for (String[] thisRow : theNameValues)
		{
			String thisKey = thisRow[0];
			String thisValue = (String) theseProperties.getProperty(thisKey);
			thisModel.setValueAt(thisValue, thisRowIndex, 1);
			thisRowIndex++;
		}
	}

	/**
	 * Load properties
	 */
	public void load()
	{
		if (thePropertyUrlString == null)
			return;

		try
		{
			URL thisUrl = new URL(thePropertyUrlString);
			Properties theseProperties = SqlProperties.load(thisUrl);
			if (theseProperties != null)
				setProperties(theseProperties);
		}
		catch (MalformedURLException thisException)
		{
		}
	}

	/**
	 * Save properties
	 */
	public void save()
	{
		if (thePropertyUrlString == null)
			return;
		try
		{
			File thisFile = new File(new URL(thePropertyUrlString).toURI());
			Properties theseProperties = getProperties();
			SqlProperties.save(theseProperties, thisFile.getAbsolutePath());
		}
		catch (MalformedURLException thisException)
		{
		}
		catch (URISyntaxException thisException)
		{
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Dialog#setVisible(boolean)
	 */
	@Override
	public void setVisible(boolean thisFlag)
	{
		if (thisFlag)
		{
			pack();
			center(this);
		}
		super.setVisible(thisFlag);
	}

	/**
	 * Center on screen
	 * 
	 * @param thisComponent
	 *        component to center
	 */
	static public void center(Component thisComponent)
	{
		Dimension thisScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension thisComponentSize = thisComponent.getSize();
		if (thisComponentSize.height > thisScreenSize.height)
			thisComponentSize.height = thisScreenSize.height;
		if (thisComponentSize.width > thisScreenSize.width)
			thisComponentSize.width = thisScreenSize.width;
		thisComponent.setLocation((thisScreenSize.width - thisComponentSize.width) / 2, (thisScreenSize.height - thisComponentSize.height) / 2);
	}

	/**
	 * Main
	 * 
	 * @param theseArgs
	 *        arguments
	 */
	static public void main(String[] theseArgs)
	{
		UIManager.put("swing.boldMetal", false);
		SqlDialog thisDialog = new SqlDialog(theseArgs.length > 0 ? theseArgs[0] : null);
		thisDialog.setModal(true);
		thisDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		thisDialog.setVisible(true);
		if (thisDialog.ok)
			thisDialog.save();
		System.exit(0);
	}
}
